﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using pos_trab_3;

namespace pos_trab_3_Testes
{
    [TestFixture]
    class ProcessadorClassificacaoTestes
    {
        /* Testes a serem feitos:
         * OK - 1 - Se o candidato está com os dados corretos
         * OK - 2 - Se a pergunta respondida chama o método certo
         * 3 - Se o cálculo da nota final é executado
         * OK - 4 - Se a Classificação chama os métodos internos
         * OK - 5 - Se a Classificação retorna uma lista ordenada
         * OK - 6 - Se o cálculo da nota final é positivo
         * ok - 7 - Se o cálculo da nota final chama o ObterValor e seta a NotaFinal
         * OK - 8 - Se o Obter Valor da Pergunta Booleana retorna 2 (True) e 0 (False)
         * OK - 9 - Se o Obter Valor da Pergunta de Multiplas Opcoes retorna de 0 a 3
         * 
         */

        [Test]
        public void InstanciaCorretamenteOCandidato()
        {
            //Arranjar
            var nome = "Fulano";
            var dataNascimento = DateTime.Now;
            var candidato = new Candidato(nome, dataNascimento);

            //Assegurar
            Assert.AreEqual(candidato.Nome, nome);
            Assert.AreEqual(candidato.DataNascimento, dataNascimento);
            Assert.IsNotNull(candidato);
        }


        [TestCase(true, 2)]
        [TestCase(false,0)]
        public void SeObterValorBooleanoRetornaOpcoesDefinidas(bool opcao, decimal valor){
            //Arranjar
                var pergunta = new PerguntaBooleana();
                pergunta.Resposta = opcao;
            //Agir
                var resultado = pergunta.obterValor();
            
            //Assegurar
                Assert.AreEqual(resultado, valor);
                Assert.IsNotNull(resultado);
                Assert.GreaterOrEqual(resultado, 0);
        }

        [TestCase("Opcao0")]
        [TestCase("Opcao1")]
        [TestCase("Opcao2")]
        [TestCase("Opcao3")]
        public void SeObterValoMultiploRetornaOpcoesDefinidas(string valor)
        {
            //Arranjar
            var pergunta = new PerguntaMultiplasOpcoes();
            //Agir
            var resultado = pergunta.obterValor();

            //Assegurar
            Assert.GreaterOrEqual(resultado,0);
            Assert.LessOrEqual(resultado, 3);
            Assert.IsNotNull(resultado);
        }
        
        [Test]
        public void ExecucaoDoCalculoDaNotaFinal()
        {
            //Arranjar
             var candidato = new CandidatoFake();

             var lista = new List<PerguntaRespondida>();
             var pergunta1 = new PerguntaBooleana();
             pergunta1.Resposta = false;
             lista.Add(pergunta1);

             candidato.PerguntasRespondidas = lista;    
            //Agir
            candidato.CalcularNotaFinalOriginal();

            //Assegurar
            var i = 0;
            Assert.AreEqual("setNotaFinal();",candidato.LogDeExecucao[i++]);
           
        }

        [Test]
        public void SeOCalculoDaNotaFinalEPositivo() 
        { 
            //Arranjar
            var candidato = new Candidato();

            candidato.Nome = "Fulano";
            candidato.DataNascimento = DateTime.Now;

            var pergunta = new PerguntaBooleana();

            pergunta.Resposta = true;
            List<PerguntaRespondida> lista = new List<PerguntaRespondida>();
            lista.Add(pergunta);
            candidato.PerguntasRespondidas = lista;

            //Agir
            var notaFinal = candidato.CalcularNotaFinal();

            //Assegurar
            Assert.GreaterOrEqual(notaFinal, 0);
        }

        [Test]
        public void SeObterValorChamaMetodoCorreto()
        {
            //Arranjar
            PerguntaRespondida perguntaBool = new PerguntaBooleanaFake();
            PerguntaRespondida perguntaMultipla = new PerguntaMultiplasOpcoesFake();

            //Assegurar
            Assert.AreEqual((decimal)ObterValorID.PerguntaBooleana, perguntaBool.obterValor());
            Assert.AreEqual((decimal)ObterValorID.PerguntaMultiplasOpcoes, perguntaMultipla.obterValor());
        }

        [Test]
        public void SeOCalculoDaNotaFinalEExecutado()
        {
            //Arranjar
            var candidato = new CandidatoFake();

            //Agir
            candidato.CalcularNotaFinal();

            //Assegurar
            var i = 0;
            Assert.AreEqual("CalcularNotaFinal();", candidato.LogDeExecucao[i++]);
        }

        [Test]
        public void SeAClassificacaoChamaOsMetodosInternos()
        {
            var processadorClassificacao = new ProcessadorClassificacaoFake();

            processadorClassificacao.Classificar(null);
            
            var i = 0;
            Assert.AreEqual("defineNotasFinais();", processadorClassificacao.LogDeExecucao[i++]);
            Assert.AreEqual("ordenaPorNotaFinalDesc();", processadorClassificacao.LogDeExecucao[i++]);
        }

        [TestCase(1)]
        [TestCase(2)]
        [TestCase(3)]
        [TestCase(4)]
        public void SeAClassificacaoRetornaUmaListaOrdenada(int quantidadeElementos)
        {
            //Arranjar
            List<Candidato> lista = preparaListaCandidatos(quantidadeElementos);
            //Agir

            var processadorClassificacao = new ProcessadorClassificacao();

            List<Candidato> listaOrdenada = processadorClassificacao.Classificar(lista);
            
            //Assegurar
            CollectionAssert.AllItemsAreNotNull(listaOrdenada);
            Assert.AreEqual(listaOrdenada.Count, lista.Count);
            Assert.AreEqual(quantidadeElementos, listaOrdenada.Count);
            switch(quantidadeElementos){
                case 1: CollectionAssert.AreEqual(lista, listaOrdenada); break;
                case 2: Assert.GreaterOrEqual(listaOrdenada[0].NotaFinal, listaOrdenada[1].NotaFinal); break;
            }
            listaOrdenada.Reverse();
            CollectionAssert.IsOrdered(listaOrdenada);
        }


        public static List<Candidato> preparaListaCandidatos(int quantidadeElementos)
        {
            var candidato1 = new Candidato("Fulano 1", DateTime.Now);
            var candidato2 = new Candidato("Fulano 2", DateTime.Now);
            var candidato3 = new Candidato("Fulano 3", DateTime.Now);
            var candidato4 = new Candidato("Fulano 4", DateTime.Now);

            var lista = new List<PerguntaRespondida>();
            var pergunta1 = new PerguntaBooleana();
            pergunta1.Resposta = false;
            lista.Add(pergunta1);
            
            var lista2 = new List<PerguntaRespondida>();
            var pergunta2 = new PerguntaBooleana();
            pergunta2.Resposta = false;
            var pergunta3 = new PerguntaMultiplasOpcoes("Opcao1");
            lista2.Add(pergunta2);
            lista2.Add(pergunta3);

            var lista3 = new List<PerguntaRespondida>();
            var pergunta4 = new PerguntaBooleana();
            pergunta4.Resposta = false;
            var pergunta5 = new PerguntaMultiplasOpcoes("Opcao3");
            lista3.Add(pergunta4);
            lista3.Add(pergunta5);

            var lista4 = new List<PerguntaRespondida>();
            var pergunta6 = new PerguntaBooleana();
            pergunta6.Resposta = true;
            var pergunta7 = new PerguntaMultiplasOpcoes("Opcao2");
            lista4.Add(pergunta6);
            lista4.Add(pergunta7);

            candidato1.PerguntasRespondidas = lista;
            candidato2.PerguntasRespondidas = lista2;
            candidato3.PerguntasRespondidas = lista3;
            candidato4.PerguntasRespondidas = lista4;

            List<Candidato> maisQueTresCandidadtos = new List<Candidato>();
            maisQueTresCandidadtos.Add(candidato1);
            maisQueTresCandidadtos.Add(candidato2);
            maisQueTresCandidadtos.Add(candidato3);
            maisQueTresCandidadtos.Add(candidato4);

            List<Candidato> tresCandidatos = new List<Candidato>();
            tresCandidatos.Add(candidato2);
            tresCandidatos.Add(candidato3);
            tresCandidatos.Add(candidato4);

            List<Candidato> doisCandidatos = new List<Candidato>();
            doisCandidatos.Add(candidato2);
            doisCandidatos.Add(candidato4);

            List<Candidato> umCandidato = new List<Candidato>();
            umCandidato.Add(candidato4);

            switch(quantidadeElementos){
                case 1: return umCandidato; 
                case 2: return doisCandidatos;
                case 3: return tresCandidatos;
                case 4: return maisQueTresCandidadtos;
                default: return null;
            }
        }
    }

    public class ProcessadorClassificacaoFake : ProcessadorClassificacao
    {
        
        public List<string> LogDeExecucao = new List<string>();
        
        public override void defineNotasFinais(List<Candidato> lista)
        {
            LogDeExecucao.Add("defineNotasFinais();");                
        }


        public override void ordenaPorNotaFinalDesc(List<Candidato> lista)
        {
            LogDeExecucao.Add("ordenaPorNotaFinalDesc();");                
        }
    }
}
